<!-- 
 * @Description: Token管理
 * @Author: huguodong 
 * @Date: 2023-12-15 15:45:10
!-->
<template>
  <el-drawer v-model="drawerVisible" destroy-on-close size="800px" title="令牌管理">
    <div class="token-manager">
      <!-- 用户信息 -->
      <el-card class="user-card" shadow="never">
        <div class="user-header">
          <el-avatar v-if="sessionInfo.avatar" :size="60" :src="sessionInfo.avatar" />
          <el-avatar v-else :size="60">
            <el-icon>
              <User />
            </el-icon>
          </el-avatar>
          <div class="user-detail">
            <div class="user-name">{{ sessionInfo.name }}</div>
            <div class="user-account">{{ sessionInfo.account }}</div>
            <el-tag v-if="sessionInfo.onlineStatus === 'ONLINE'" size="small" type="success">在线</el-tag>
            <el-tag v-else size="small" type="info">离线</el-tag>
          </div>
        </div>
      </el-card>

      <!-- Token列表 -->
      <div class="token-list">
        <div class="list-header">
          <span class="title">令牌列表 ({{ sessionInfo.tokenSignList?.length || 0 }})</span>
          <el-button :disabled="selectedTokens.length === 0" size="small" type="danger" @click="onBatchExitToken">
            批量强退 ({{ selectedTokens.length }})
          </el-button>
        </div>

        <el-empty v-if="!sessionInfo.tokenSignList || sessionInfo.tokenSignList.length === 0" description="暂无令牌" />

        <div v-else class="token-items">
          <el-card
            v-for="(token, index) in sessionInfo.tokenSignList"
            :key="index"
            :class="{ selected: selectedTokens.includes(token.token) }"
            class="token-item"
            shadow="hover"
            @click="toggleTokenSelection(token.token)"
          >
            <div class="token-header">
              <el-checkbox :model-value="selectedTokens.includes(token.token)" @change="toggleTokenSelection(token.token)" @click.stop />
              <el-tag :type="token.loginClientType === 'B' ? 'primary' : 'success'" size="small">
                {{ token.loginClientType === "B" ? "B端" : "C端" }}
              </el-tag>
              <el-tag v-if="token.clientIds.length > 0" size="small" type="success">
                <el-icon class="is-loading">
                  <Loading />
                </el-icon>
                在线
              </el-tag>
              <el-tag v-else size="small" type="info">离线</el-tag>
            </div>

            <div class="token-content">
              <div class="token-info">
                <div class="info-row">
                  <el-icon>
                    <Monitor />
                  </el-icon>
                  <span class="label">设备:</span>
                  <span class="value">{{ token.device || "未知设备" }}</span>
                </div>
                <div class="info-row">
                  <el-icon>
                    <Clock />
                  </el-icon>
                  <span class="label">过期时间:</span>
                  <span class="value">{{ token.tokenTimeout }}</span>
                </div>
                <div class="info-row">
                  <el-icon>
                    <Timer />
                  </el-icon>
                  <span class="label">剩余时间:</span>
                  <span class="value">{{ token.tokenRemain }}</span>
                </div>
                <div class="info-row">
                  <el-icon>
                    <Key />
                  </el-icon>
                  <span class="label">Token:</span>
                  <span class="value token-text">{{ token.token }}</span>
                  <el-button link size="small" type="primary" @click.stop="copyToken(token.token)">
                    <el-icon>
                      <CopyDocument />
                    </el-icon>
                    复制
                  </el-button>
                </div>
              </div>

              <!-- 进度条 -->
              <div class="token-progress">
                <el-progress
                  :color="getProgressColor(token.tokenRemainPercent)"
                  :percentage="Math.round(token.tokenRemainPercent * 100)"
                  :stroke-width="6"
                />
              </div>
            </div>

            <div class="token-footer">
              <el-button link size="small" type="danger" @click.stop="onExitToken(token.token)">
                <el-icon>
                  <Close />
                </el-icon>
                强退此令牌
              </el-button>
            </div>
          </el-card>
        </div>
      </div>
    </div>
  </el-drawer>
</template>

<script lang="ts" name="tokenManager" setup>
import { Session, sessionApi } from "@/api";
import { Clock, Close, CopyDocument, Key, Loading, Monitor, Timer, User } from "@element-plus/icons-vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { useClipboard } from "@vueuse/core";

// Props
const props = defineProps<{
  clientType: "B" | "C";
}>();

// Emits
const emit = defineEmits<{
  refresh: [];
}>();

// 抽屉显示
const drawerVisible = ref(false);

// 会话信息
const sessionInfo = ref<Session.SessionInfo>({
  id: 0,
  account: "",
  name: "",
  avatar: "",
  onlineStatus: "",
  latestLoginIp: "",
  latestLoginAddress: "",
  latestLoginTime: "",
  tokenCount: 0,
  tokenSignList: []
});

// 选中的Token
const selectedTokens = ref<string[]>([]);

// 剪贴板
const { copy } = useClipboard();

/**
 * 打开抽屉
 * @param record 记录
 */
function onOpen(record: Session.SessionInfo) {
  drawerVisible.value = true;
  sessionInfo.value = record;
  selectedTokens.value = [];
}

/**
 * 切换Token选择
 * @param token Token
 */
function toggleTokenSelection(token: string) {
  const index = selectedTokens.value.indexOf(token);
  if (index > -1) {
    selectedTokens.value.splice(index, 1);
  } else {
    selectedTokens.value.push(token);
  }
}

/**
 * 复制Token
 * @param token Token
 */
async function copyToken(token: string) {
  try {
    await copy(token);
    ElMessage.success("Token已复制到剪贴板");
  } catch (error) {
    ElMessage.error("复制失败");
  }
}

/**
 * 获取进度条颜色
 * @param percent 百分比
 */
function getProgressColor(percent: number): string {
  if (percent > 0.5) return "#67c23a";
  if (percent > 0.2) return "#e6a23c";
  return "#f56c6c";
}

/**
 * 强退单个Token
 * @param token Token
 */
async function onExitToken(token: string) {
  try {
    await ElMessageBox.confirm("确定要强退此令牌吗?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    });

    const api = props.clientType === "B" ? sessionApi.exitTokenB : sessionApi.exitTokenC;
    await api({ id: sessionInfo.value.id, tokens: [token] });

    ElMessage.success("强退成功");
    drawerVisible.value = false;
    emit("refresh");
  } catch (error) {
    if (error !== "cancel") {
      ElMessage.error("强退失败");
    }
  }
}

/**
 * 批量强退Token
 */
async function onBatchExitToken() {
  if (selectedTokens.value.length === 0) {
    ElMessage.warning("请选择要强退的令牌");
    return;
  }

  try {
    await ElMessageBox.confirm(`确定要强退选中的 ${selectedTokens.value.length} 个令牌吗?`, "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    });

    const api = props.clientType === "B" ? sessionApi.exitTokenB : sessionApi.exitTokenC;
    await api({ id: sessionInfo.value.id, tokens: selectedTokens.value });

    ElMessage.success("批量强退成功");
    drawerVisible.value = false;
    emit("refresh");
  } catch (error) {
    if (error !== "cancel") {
      ElMessage.error("批量强退失败");
    }
  }
}

// 暴露方法
defineExpose({ onOpen });
</script>

<style lang="scss" scoped>
.token-manager {
  .user-card {
    margin-bottom: 20px;

    .user-header {
      display: flex;
      align-items: center;
      gap: 20px;

      .user-detail {
        flex: 1;

        .user-name {
          font-size: 20px;
          font-weight: bold;
          color: #303133;
          margin-bottom: 8px;
        }

        .user-account {
          font-size: 14px;
          color: #909399;
          margin-bottom: 8px;
        }
      }
    }
  }

  .token-list {
    .list-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 16px;

      .title {
        font-size: 16px;
        font-weight: bold;
        color: #303133;
      }
    }

    .token-items {
      display: flex;
      flex-direction: column;
      gap: 12px;

      .token-item {
        cursor: pointer;
        transition: all 0.3s;

        &.selected {
          border-color: var(--el-color-primary);
          box-shadow: 0 0 0 2px var(--el-color-primary-light-9);
        }

        &:hover {
          transform: translateY(-2px);
        }

        .token-header {
          display: flex;
          align-items: center;
          gap: 8px;
          margin-bottom: 12px;
        }

        .token-content {
          .token-info {
            .info-row {
              display: flex;
              align-items: center;
              gap: 8px;
              margin-bottom: 8px;
              font-size: 13px;

              .el-icon {
                color: #909399;
              }

              .label {
                color: #606266;
                min-width: 70px;
              }

              .value {
                flex: 1;
                color: #303133;

                &.token-text {
                  font-family: monospace;
                  font-size: 12px;
                  word-break: break-all;
                }
              }
            }
          }

          .token-progress {
            margin-top: 12px;
          }
        }

        .token-footer {
          margin-top: 12px;
          padding-top: 12px;
          border-top: 1px solid #f0f0f0;
          display: flex;
          justify-content: flex-end;
        }
      }
    }
  }
}

:deep(.el-card__body) {
  padding: 16px;
}

:deep(.el-progress__text) {
  font-size: 12px !important;
}

:deep(.is-loading) {
  margin-right: 4px;
}
</style>
